COMP3153/9153 Algorithmic Verification Term 1, 2020

Code (Week 3)

Table of Contents

1 Introduction

1.1 Hello World

proctype A() {
    printf("Hello world, I am process %d!\n",_pid);
}

init {
    run A();
    run A();
}

1.2 Counters

#define TIMES 10
byte    n = 0;

proctype P() {
  byte i =0;
  byte temp;
  do 
  :: i < TIMES ->
    temp = n;
    n = temp + 1;
    i = i + 1;
  :: else -> break;
  od
}

init {
  atomic {
    run P();
    run P()
  }
  (_nr_pr == 1);
  printf("The value is %d\n", n);
  assert(n != 1)
}

2 Critical Sections

2.1 Header File

inline critical_section() {
     printf("MSC: %d in CS\n", _pid);
}

inline non_critical_section() {
  printf("MSC: %d in non-CS\n", _pid);
  do               /* non-deterministically choose how
                      long to stay, even forever */
    :: true ->
         skip
    :: true ->
         break
  od
}

2.2 First Attempt

#include "critical2.h"

byte turn = 1;


active proctype p() {
  do
    :: non_critical_section();
wap:   turn == 1;               /* await */
csp:   critical_section(); 
       turn = 2
  od
}

active proctype q() {
  do
    :: non_critical_section();
waq:   turn == 2;               /* await */
csq:   critical_section();
       turn = 1
  od
}



ltl mutex { always (!(p@csp && q@csq)) }
ltl sfp {always (  p@wap implies eventually p@csp ) }
ltl sfq {always (  q@waq implies eventually q@csq ) }
/*
We can use an auxiliary variable with a monitor process like so:
active proctype monitor() {
    do
    :: assert(inCS != 2);
    od
}
*/

/*
A more idiomatic way is to use never claims
never {
    do :: inCS >= 2 -> break
       :: else 
    od
}

We can avoid auxiliary variables using label assertions:
never {
    do :: p@csp && q@csq -> break
       :: else 
    od
}

We can also just state LTL directly as above.
*/

2.3 Second Attempt

#include "critical2.h"

bool wantp = false, wantq = false;

active proctype p() {
  do
    :: non_critical_section();
wap:   wantp = true; 
       wantq == false;  /* await */
csp:   critical_section();
       wantp = false
  od
}

active proctype q() {
  do
    :: non_critical_section();
       /* Originally this came before the await,
           but it lead to mutex violation */
waq:   wantq = true;
       wantp == false; /* await */
csq:   critical_section();
       wantq = false
  od
}
ltl mutex { always (!(p@csp && q@csq)) }

2.4 Third Attempt (Peterson's Algorithm)

#include "critical2.h"
byte wantp = 0;
byte wantq = 0;
byte turn = 1;
active proctype p() {
  do
    :: non_critical_section();
wap:   wantp = true; turn = 1;
       (wantq == false) || (turn == 0);
csp:   critical_section(); 
       wantp = false;
  od
}

active proctype q() {
  do
    :: non_critical_section();
waq:   wantq = true; turn = 0;
       (wantp == false) || (turn == 1);
csq:   critical_section();
       wantq = false;
  od
}

ltl mutex { always (!(p@csp && q@csq)) }
ltl sf { always (p@wap implies eventually p@csp)}

/* needs fairness for sf */

3 Channels

3.1 Locks using Synchronous Channels

#include "critical2.h"
mtype = {LOCK, UNLOCK};

proctype lock( chan l ) {
    do :: l ? LOCK; l ? UNLOCK; od 
}
proctype p(chan l) {
  do
    :: non_critical_section();
wap:   l ! LOCK;
csp:   critical_section(); 
       l ! UNLOCK;
  od
}

proctype q(chan l) {
  do
    :: non_critical_section();
waq:   l ! LOCK;
csq:   critical_section();
       l ! UNLOCK;
  od
}

init {
    chan l = [0] of { mtype };
    run p(l);
    run q(l);
}

ltl mutex { [](!(p@csp && q@csq)) }

3.2 Locks using Asynchronous Channels

#include "critical2.h"
proctype p(chan l) {
  do
    :: non_critical_section();
wap:   l ? 1;
csp:   critical_section(); 
       l ! 1;
  od
}

proctype q(chan l) {
  do
    :: non_critical_section();
waq:   l ? 1;
csq:   critical_section();
       l ! 1;
  od
}

init {
    chan l = [1] of { bit };
    l!1;
    run p(l);
    run q(l);
}

ltl mutex { [](!(p@csp && q@csq)) }

2020-05-15 Fri 00:10

Announcements RSS